package mws.redis.src.config;

import io.lettuce.core.ClientOptions;
import io.lettuce.core.SocketOptions;
import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.resource.DefaultClientResources;
import io.netty.util.internal.StringUtil;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;

import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 *   关闭 配置类的 动态代理 因为只要用一次 一个单例就可以了
 *   以下是标准写法
 *
 *   另
 *   从稳定性和低侵入性来看，@Import 显式导入更优；
 *   若类较多，@ComponentScan("精确子包路径") 也是可行的。两种方式都符合外部包自动配置的规范。
 *
 *
 */

@EnableConfigurationProperties(RedisOfProperties.class)
@ComponentScan("mws.redis.src") //
@Configuration(proxyBeanMethods = false)
@AutoConfiguration
public class RedisTemplateConfig {

@Primary
@Bean(name = "redisTemplateOfString")
public RedisTemplate<String,String> redisTemplate(RedisOfProperties redisOfProperties) {
    Integer serializerType = redisOfProperties.getSerializerType();
    if (serializerType==null || serializerType.equals(0)) {
//
//
//        RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration();
//        if(StringUtil.isNullOrEmpty(redisOfProperties.getDatabaseNum()) ){
//            database = 0;
//        }else{
//            int i = Integer.parseInt(redisOfProperties.getDatabaseNum());
//            if (i > 10 || i < 0) database = 0;
//            else database = i;
//        }
//
//        standaloneConfiguration.setDatabase(database);
//        String hostname = redisOfProperties.getHost();
//        int port = 6379;
//
//        String password = redisOfProperties.getPassword();
//        if(!StringUtil.isNullOrEmpty(redisOfProperties.getPort()))standaloneConfiguration.setPort(Integer.parseInt(redisOfProperties.getPort()));
//        if(!StringUtil.isNullOrEmpty(hostname) && !StringUtil.isNullOrEmpty(password))standaloneConfiguration.setHostName(hostname);
//        if(!StringUtil.isNullOrEmpty(password)) standaloneConfiguration.setPassword(password);

//        LettuceConnectionFactory lettuceConnectionFactory = new LettuceConnectionFactory(standaloneConfiguration);
//        lettuceConnectionFactory.afterPropertiesSet();

 LettuceConnectionFactory lettuceConnectionFactory = createLettuceConnectionFactory(redisOfProperties);
 lettuceConnectionFactory.afterPropertiesSet();
        RedisTemplate<String, String> objectObjectRedisTemplate = new RedisTemplate<>();
        objectObjectRedisTemplate.setKeySerializer(new StringRedisSerializer());
        objectObjectRedisTemplate.setValueSerializer(new StringRedisSerializer());
        objectObjectRedisTemplate.setHashKeySerializer(new StringRedisSerializer());
        objectObjectRedisTemplate.setHashValueSerializer(new StringRedisSerializer());
        objectObjectRedisTemplate.setConnectionFactory(lettuceConnectionFactory);
        return objectObjectRedisTemplate;
    }else if (serializerType.equals(1)){

        throw new IllegalArgumentException("serializerType 1 not support");
    }

    throw new IllegalArgumentException("serializerType Other not support");

}

    public LettuceConnectionFactory createLettuceConnectionFactory(RedisOfProperties redisOfProperties) {
        // 1. 基础配置
        RedisStandaloneConfiguration standaloneConfiguration = new RedisStandaloneConfiguration();

        // 设置主机名
        String hostname = redisOfProperties.getHost();
        if (!StringUtil.isNullOrEmpty(hostname)) {
            standaloneConfiguration.setHostName(hostname);
        }

        // 设置端口
        Integer port = redisOfProperties.getPort();
        if (port != null) {
            standaloneConfiguration.setPort(port);
        }

        // 设置密码
        String password = redisOfProperties.getPassword();
        if (!StringUtil.isNullOrEmpty(password)) {
            standaloneConfiguration.setPassword(password);
        }

        // 设置数据库编号
        Integer databaseNum = redisOfProperties.getDatabaseNum();
        if (databaseNum != null) {
            standaloneConfiguration.setDatabase(databaseNum);
        }

        // 2. Lettuce连接池配置
        RedisOfProperties.LettucePool lettucePool = redisOfProperties.getLettuce();
        if (lettucePool == null) {
            lettucePool = new RedisOfProperties.LettucePool(); // 使用默认配置
        }

        // 连接池通用配置
        GenericObjectPoolConfig<?> poolConfig = new GenericObjectPoolConfig<>();
        poolConfig.setMaxTotal(lettucePool.getMaxActive());
        poolConfig.setMaxIdle(lettucePool.getMaxIdle());
        poolConfig.setMinIdle(lettucePool.getMinIdle());
        // 转换Duration为毫秒（如果maxWait为-1则表示无限制）
        long maxWaitMillis = lettucePool.getMaxWait().toMillis();
        poolConfig.setMaxWaitMillis(maxWaitMillis);

        // 3. Lettuce客户端配置
        ClientResources clientResources = DefaultClientResources.create();

        LettuceClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder()
                .clientResources(clientResources)
                .poolConfig(poolConfig)
                .commandTimeout(lettucePool.getTimeout()) // 命令超时时间
                .shutdownTimeout(lettucePool.getShutdownTimeout()) // 关闭超时时间
                .clientOptions(ClientOptions.builder()
                        .socketOptions(SocketOptions.builder()
                                .connectTimeout(lettucePool.getTimeout()) // 连接超时时间
                                .build())
                        .build())
                .build();

        // 4. 创建连接工厂
        return new LettuceConnectionFactory(standaloneConfiguration, clientConfiguration);
    }

}
